package cn.jtool.dig.common.netty;

import cn.jtool.dig.common.BizException;
import cn.jtool.dig.common.model.Session;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.util.Strings;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

@Slf4j
public class SessionManager {

    private final static AtomicLong sessionIdGen = new AtomicLong(10000);

    private static Map<String, AttributeKey<Object>> attributeKeys = Maps.newConcurrentMap();

    public static void setAttribute(ChannelHandlerContext ctx, String attributeKey, Object attributeValue){
        AttributeKey<Object> attributeKeyObject = attributeKeys.get(attributeKey);
        if(Objects.isNull(attributeKeyObject)){
            attributeKeyObject = AttributeKey.newInstance(attributeKey);
            attributeKeys.put(attributeKey, attributeKeyObject);
        }
        ctx.channel().attr(attributeKeyObject).setIfAbsent(attributeValue);
    }

    public static Object getAttribute(ChannelHandlerContext ctx, String attributeKey){
        AttributeKey<Object> attributeKeyObject = attributeKeys.get(attributeKey);
        if(Objects.isNull(attributeKeyObject)){
            throw new BizException(attributeKey + " 属性不存在");
        }
        return ctx.channel().attr(attributeKeyObject).get();
    }

    public static Integer getAttributeForInteger(ChannelHandlerContext ctx, String attributeKey){
        Object attrValue = getAttribute(ctx, attributeKey);
        if(Objects.nonNull(attrValue)){
            return Integer.valueOf(attrValue.toString());
        }
        return 0;
    }
    public static long getAttributeForLong(ChannelHandlerContext ctx, String attributeKey){
        Object attrValue = getAttribute(ctx, attributeKey);
        if(Objects.nonNull(attrValue)){
            return Long.parseLong(attrValue.toString());
        }
        return 0;
    }

    public static String getAttributeForString(ChannelHandlerContext ctx, String attributeKey){
        Object attrValue = getAttribute(ctx, attributeKey);
        if(Objects.nonNull(attrValue)){
            return String.valueOf(attrValue);
        }
        return Strings.EMPTY;
    }

    public static boolean getAttributeForBoolean(ChannelHandlerContext ctx, String attributeKey){
        Object attrValue = getAttribute(ctx, attributeKey);
        if(Objects.nonNull(attrValue)){
            return Boolean.valueOf(String.valueOf(attrValue));
        }
        return Boolean.FALSE;
    }

    /**
     * 生成sessionId
     * @param ctx
     * @return
     */
    public static long getSessionId(ChannelHandlerContext ctx){
        return getAttributeForLong(ctx, SessionAttributeKey.SESSION_ID.getCode());
    }

    public static long setSessionId(ChannelHandlerContext ctx){
        long sessionId = sessionIdGen.incrementAndGet();
        setAttribute(ctx, SessionAttributeKey.SESSION_ID.getCode(), sessionId);
        return sessionId;
    }


    private static Map<Long, Session> sessionMap = Maps.newConcurrentMap();

    public static List<Session> getSession(){
        return Lists.newArrayList(sessionMap.values());
    }

    public static List<Session> getSession(Session.SessionType sessionType){
        List<Session> sessions = getSession();
        if(CollectionUtils.isNotEmpty(sessions)){
            return sessions.stream().filter(session -> session.getSessionType() == sessionType).collect(Collectors.toList());
        }
        return Lists.newArrayList();
    }

    public static Session getSession(long sessionId){
        return sessionMap.get(sessionId);
    }

    public static void addSession(Session session){
        sessionMap.put(session.getId(), session);
    }

    public static void removeSession(Long sessionId){
        if(Objects.nonNull(sessionId)){
            sessionMap.remove(sessionId);
        }
    }

    public static void remove(){
        sessionMap.clear();
    }

}
